<?php /** @noinspection PhpUndefinedClassInspection */

namespace Dreamcat\Components\QuickMock\Cases;

use Dreamcat\Components\QuickMock\Error\MockFactoryException;
use Dreamcat\Components\QuickMock\Factory\QuickMockFactory;
use Dreamcat\Components\QuickMock\Resource\DemoInterface;
use Dreamcat\Components\QuickMock\Resource\DemoProxy;
use Dreamcat\Components\QuickMock\Resource\Helper;
use Dreamcat\Components\QuickMock\Resource\ProxyInvokeParams;
use Dreamcat\Components\QuickMock\Resource\StaticInterface;
use PHPUnit\Framework\TestCase;

/**
 * QuickMockFactory测试用例
 * @author vijay
 */
class QuickMockTest extends TestCase
{
    /**
     * 测试常规场景
     * @return void
     */
    public function testNormal()
    {
        $proxy = new DemoProxy();
        $factory = new QuickMockFactory();
        /** @var DemoInterface $mock */
        $mock = $factory->createMock(DemoInterface::class, $proxy);

        self::assertTrue(is_object($mock), "mock结果非对象");
        self::assertTrue(is_subclass_of($mock, DemoInterface::class), "mock对象的接口不正确");

        $checkList = [
            [
                "testFunction",
                [],
            ],
            [
                "testWithParm",
                [
                    $mock,
                    [uniqid()],
                ],
            ],
            [
                "testWithParm",
                [
                    $mock,
                    [uniqid()],
                    uniqid("p3-"),
                ],
            ],
        ];
        foreach ($checkList as $item) {
            try {
                call_user_func_array(
                    [
                        $mock,
                        $item[0],
                    ],
                    $item[1]
                );
            } catch (ProxyInvokeParams $params) {
                $this->checkInvoke($mock, $item[0], $item[1], $params);
            }
        }
    }

    /**
     * 检查调用情况
     * @param mixed $mock mock对象
     * @param string $methodName 调用的方法名
     * @param array $args 调用参数
     * @param ProxyInvokeParams $invokeParams 代理抛出的信息
     * @return void
     */
    private function checkInvoke($mock, $methodName, $args, ProxyInvokeParams $invokeParams)
    {
        self::assertTrue(Helper::compareObj($invokeParams->obj, $mock), "传入对象不一致");
        self::assertEquals(get_class($mock), $invokeParams->method->getDeclaringClass()->getName(), "传入的反射类名不一致");
        self::assertEquals($methodName, $invokeParams->method->getName(), "传入的反射方法名不一致");
        self::assertEquals(count($args), count($invokeParams->args), "传入的参数个数不一致");
        foreach ($args as $index => $val) {
            self::assertArrayHasKey($index, $invokeParams->args, "传入的参数不存在 {$index}");
            self::assertEquals($val, $invokeParams->args[$index], "传入的参数 {$index} 不一致");
        }
    }

    /**
     * 测试接口不存在的异常
     * @return void
     */
    public function testInterfaceNotExists()
    {
        $this->expectException(MockFactoryException::class);
        $this->expectExceptionCode(MockFactoryException::INTERFACE_NOT_EXISTS);
        $className = uniqid("class_");
        $this->expectExceptionMessage("interface not exists [{$className}]");
        (new QuickMockFactory())->createMock($className, new DemoProxy());
    }

    public function testStaticNotSupport()
    {
        $this->expectException(MockFactoryException::class);
        $this->expectExceptionCode(MockFactoryException::STATIC_METHOD_NOT_SUPPORT);
        $class = StaticInterface::class;
        $this->expectExceptionMessage("method [{$class}::sf] is static not support mock");
        (new QuickMockFactory())->createMock(StaticInterface::class, new DemoProxy());
    }
}

# end of file
